package top.ljlgithub.api.shiro.realm;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import top.ljlgithub.api.bean.Manager;
import top.ljlgithub.api.mapper.ManagerMapper;

import java.security.Security;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
 * @ClassName
 * @Description TODO
 * @Author L1470
 * @Date 2021/4/23 21:22
 * @Version 1.0
 **/

/**
 * 同时开启身份验证和权限验证，需要继承 AuthorizingRealm
 * 并实现其  doGetAuthenticationInfo()和 doGetAuthorizationInfo 两个方法
 */
@SuppressWarnings("serial")
public class ShiroRealm extends AuthorizingRealm {
    @Autowired
    ManagerMapper managerMapper;

    /**
     * 限定这个 Realm 只处理 UsernamePasswordToken
     */

//  会先判断传过来的token是不是UsernamePasswordToken，不是的话会抛异常
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken;
    }

    /**
     * 查询数据库，将获取到的用户安全数据封装返回
     */
    @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 从 AuthenticationToken 中获取当前用户名，这个AuthenticationToken是传过来的userNamePasswordToken
        String username = (String) token.getPrincipal();
        //从数据库中通过用户名查询用户
        Manager manager = managerMapper.findManagerByUsername(username);
         //用户不存在返回空，会抛异常
        if (manager == null) {
            return null;
        }

         //用户被锁定
        if (!manager.getState()) {
            throw new LockedAccountException("该用户已被锁定,暂时无法登录！");
        }

        // 获取注册时的随机盐
        ByteSource credentialsSalt = ByteSource.Util.bytes(manager.getSalt());

        /**
         * 将获取到的用户数据封装成 AuthenticationInfo 对象返回，此处封装为 SimpleAuthenticationInfo 对象，然后会去凭证匹配器进行验证。
         *  参数1. 认证的实体信息，可以是从数据库中获取到的用户实体类对象或者用户名
         *  参数2. 查询获取到的真正的登录密码
         *  参数3. 盐值
         *  参数4. 当前 Realm 对象的名称，直接调用父类的 getName() 方法即可
         */

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(manager, manager.getPwd(), credentialsSalt, getName());
        return info;
    }

    /**
     * 查询数据库，将获取到的用户的角色及权限信息返回
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

}
